"""
错误处理器模块

提供统一的错误处理、恢复策略和错误报告功能
"""

import asyncio
import logging
import traceback
from typing import Dict, Any, Optional, Callable, List, Union
from datetime import datetime, timedelta
from enum import Enum
from dataclasses import dataclass, field

from .exceptions import XCQuantError
from .unified_core import unified_logger


class ErrorSeverity(Enum):
    """错误严重程度"""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class RecoveryAction(Enum):
    """恢复动作类型"""
    RETRY = "retry"
    FALLBACK = "fallback"
    SKIP = "skip"
    STOP = "stop"
    RESTART = "restart"


@dataclass
class ErrorContext:
    """错误上下文信息"""
    error: Exception
    component: str
    operation: str
    timestamp: datetime = field(default_factory=datetime.now)
    severity: ErrorSeverity = ErrorSeverity.MEDIUM
    retry_count: int = 0
    max_retries: int = 3
    context_data: Dict[str, Any] = field(default_factory=dict)
    recovery_actions: List[RecoveryAction] = field(default_factory=list)


@dataclass
class RecoveryStrategy:
    """恢复策略"""
    name: str
    action: RecoveryAction
    condition: Callable[[ErrorContext], bool]
    handler: Callable[[ErrorContext], Any]
    max_attempts: int = 3
    delay: float = 1.0
    backoff_factor: float = 2.0


class ErrorHandler:
    """统一错误处理器"""
    
    def __init__(self):
        self.logger = unified_logger.get_logger("error_handler")
        self.recovery_strategies: Dict[str, List[RecoveryStrategy]] = {}
        self.error_history: List[ErrorContext] = []
        self.error_callbacks: List[Callable[[ErrorContext], None]] = []
        self.circuit_breakers: Dict[str, Dict[str, Any]] = {}
        
        # 默认恢复策略
        self._setup_default_strategies()
    
    def _setup_default_strategies(self):
        """设置默认恢复策略"""
        
        # 网络错误恢复策略
        self.register_recovery_strategy(
            "NetworkError",
            RecoveryStrategy(
                name="network_retry",
                action=RecoveryAction.RETRY,
                condition=lambda ctx: ctx.retry_count < 3,
                handler=self._retry_with_backoff,
                max_attempts=3,
                delay=1.0,
                backoff_factor=2.0
            )
        )
        
        # API错误恢复策略
        self.register_recovery_strategy(
            "ExchangeAPIError",
            RecoveryStrategy(
                name="api_fallback",
                action=RecoveryAction.FALLBACK,
                condition=lambda ctx: hasattr(ctx.error, 'http_status') and ctx.error.http_status >= 500,
                handler=self._api_fallback,
                max_attempts=2
            )
        )
        
        # 数据缺失恢复策略
        self.register_recovery_strategy(
            "DataMissingError",
            RecoveryStrategy(
                name="data_recovery",
                action=RecoveryAction.RETRY,
                condition=lambda ctx: ctx.retry_count < 2,
                handler=self._data_recovery,
                max_attempts=2
            )
        )
        
        # 风险控制恢复策略
        self.register_recovery_strategy(
            "RiskControlError",
            RecoveryStrategy(
                name="risk_stop",
                action=RecoveryAction.STOP,
                condition=lambda ctx: hasattr(ctx.error, 'risk_level') and ctx.error.risk_level == "critical",
                handler=self._emergency_stop,
                max_attempts=1
            )
        )
    
    def register_recovery_strategy(self, error_type: str, strategy: RecoveryStrategy):
        """注册恢复策略"""
        if error_type not in self.recovery_strategies:
            self.recovery_strategies[error_type] = []
        self.recovery_strategies[error_type].append(strategy)
        self.logger.info(f"注册恢复策略: {error_type} -> {strategy.name}")
    
    def register_error_callback(self, callback: Callable[[ErrorContext], None]):
        """注册错误回调"""
        self.error_callbacks.append(callback)
    
    async def handle_error(self, error: Exception, component: str, operation: str, 
                          context_data: Dict[str, Any] = None) -> Any:
        """
        处理错误
        
        Args:
            error: 异常对象
            component: 组件名称
            operation: 操作名称
            context_data: 上下文数据
            
        Returns:
            恢复结果或重新抛出异常
        """
        # 创建错误上下文
        error_context = ErrorContext(
            error=error,
            component=component,
            operation=operation,
            context_data=context_data or {},
            severity=self._determine_severity(error)
        )
        
        # 记录错误
        self._log_error(error_context)
        
        # 添加到历史记录
        self.error_history.append(error_context)
        
        # 检查熔断器
        if self._check_circuit_breaker(component, operation):
            self.logger.warning(f"熔断器触发: {component}.{operation}")
            raise error
        
        # 执行错误回调
        for callback in self.error_callbacks:
            try:
                callback(error_context)
            except Exception as e:
                self.logger.error(f"错误回调执行失败: {e}")
        
        # 尝试恢复
        recovery_result = await self._attempt_recovery(error_context)
        
        if recovery_result is not None:
            return recovery_result
        
        # 如果无法恢复，重新抛出异常
        raise error
    
    async def _attempt_recovery(self, error_context: ErrorContext) -> Any:
        """尝试错误恢复"""
        error_type = type(error_context.error).__name__
        strategies = self.recovery_strategies.get(error_type, [])
        
        for strategy in strategies:
            if strategy.condition(error_context):
                self.logger.info(f"尝试恢复策略: {strategy.name}")
                
                try:
                    result = await self._execute_recovery_strategy(strategy, error_context)
                    if result is not None:
                        self.logger.info(f"恢复成功: {strategy.name}")
                        return result
                except Exception as e:
                    self.logger.error(f"恢复策略失败: {strategy.name}, {e}")
                    continue
        
        return None
    
    async def _execute_recovery_strategy(self, strategy: RecoveryStrategy, 
                                       error_context: ErrorContext) -> Any:
        """执行恢复策略"""
        for attempt in range(strategy.max_attempts):
            try:
                if strategy.action == RecoveryAction.RETRY:
                    if attempt > 0:
                        delay = strategy.delay * (strategy.backoff_factor ** (attempt - 1))
                        await asyncio.sleep(delay)
                
                result = await strategy.handler(error_context)
                return result
                
            except Exception as e:
                if attempt == strategy.max_attempts - 1:
                    raise e
                continue
        
        return None
    
    def _determine_severity(self, error: Exception) -> ErrorSeverity:
        """确定错误严重程度"""
        if isinstance(error, XCQuantError):
            if hasattr(error, 'risk_level') and error.risk_level == "critical":
                return ErrorSeverity.CRITICAL
            elif "API" in type(error).__name__:
                return ErrorSeverity.HIGH
            elif "Data" in type(error).__name__:
                return ErrorSeverity.MEDIUM
        
        # 根据异常类型判断
        critical_errors = ["SystemExit", "KeyboardInterrupt", "MemoryError"]
        if type(error).__name__ in critical_errors:
            return ErrorSeverity.CRITICAL
        
        return ErrorSeverity.MEDIUM
    
    def _log_error(self, error_context: ErrorContext):
        """记录错误日志"""
        error_info = {
            'component': error_context.component,
            'operation': error_context.operation,
            'error_type': type(error_context.error).__name__,
            'error_message': str(error_context.error),
            'severity': error_context.severity.value,
            'retry_count': error_context.retry_count,
            'context_data': error_context.context_data
        }
        
        if error_context.severity == ErrorSeverity.CRITICAL:
            self.logger.critical(f"严重错误: {error_info}")
        elif error_context.severity == ErrorSeverity.HIGH:
            self.logger.error(f"高级错误: {error_info}")
        else:
            self.logger.warning(f"错误: {error_info}")
        
        # 记录详细的堆栈跟踪
        self.logger.debug(f"堆栈跟踪: {traceback.format_exc()}")
    
    def _check_circuit_breaker(self, component: str, operation: str) -> bool:
        """检查熔断器状态"""
        key = f"{component}.{operation}"
        
        if key not in self.circuit_breakers:
            self.circuit_breakers[key] = {
                'failure_count': 0,
                'last_failure': None,
                'state': 'closed'  # closed, open, half_open
            }
        
        breaker = self.circuit_breakers[key]
        
        # 如果熔断器打开，检查是否可以半开
        if breaker['state'] == 'open':
            if breaker['last_failure']:
                time_since_failure = datetime.now() - breaker['last_failure']
                if time_since_failure > timedelta(minutes=5):  # 5分钟后尝试半开
                    breaker['state'] = 'half_open'
                    return False
            return True
        
        return False
    
    def _update_circuit_breaker(self, component: str, operation: str, success: bool):
        """更新熔断器状态"""
        key = f"{component}.{operation}"
        
        if key not in self.circuit_breakers:
            return
        
        breaker = self.circuit_breakers[key]
        
        if success:
            breaker['failure_count'] = 0
            breaker['state'] = 'closed'
        else:
            breaker['failure_count'] += 1
            breaker['last_failure'] = datetime.now()
            
            # 失败次数超过阈值，打开熔断器
            if breaker['failure_count'] >= 5:
                breaker['state'] = 'open'
                self.logger.warning(f"熔断器打开: {key}")
    
    async def _retry_with_backoff(self, error_context: ErrorContext) -> Any:
        """带退避的重试策略"""
        error_context.retry_count += 1
        self.logger.info(f"重试操作: {error_context.operation} (第{error_context.retry_count}次)")
        
        # 这里应该重新执行原始操作
        # 由于我们无法直接重新执行，返回None表示需要上层处理
        return None
    
    async def _api_fallback(self, error_context: ErrorContext) -> Any:
        """API降级策略"""
        self.logger.info(f"API降级: {error_context.operation}")
        
        # 可以实现备用API调用或缓存数据返回
        # 这里返回None表示降级失败
        return None
    
    async def _data_recovery(self, error_context: ErrorContext) -> Any:
        """数据恢复策略"""
        self.logger.info(f"数据恢复: {error_context.operation}")
        
        # 可以实现数据重新下载或使用历史数据
        return None
    
    async def _emergency_stop(self, error_context: ErrorContext) -> Any:
        """紧急停止策略"""
        self.logger.critical(f"紧急停止: {error_context.operation}")
        
        # 执行紧急停止操作
        # 这里可以停止所有交易、发送告警等
        return None
    
    def get_error_statistics(self) -> Dict[str, Any]:
        """获取错误统计信息"""
        if not self.error_history:
            return {}
        
        # 按错误类型统计
        error_types = {}
        severity_counts = {severity.value: 0 for severity in ErrorSeverity}
        
        for error_ctx in self.error_history:
            error_type = type(error_ctx.error).__name__
            error_types[error_type] = error_types.get(error_type, 0) + 1
            severity_counts[error_ctx.severity.value] += 1
        
        # 最近24小时的错误
        recent_errors = [
            ctx for ctx in self.error_history
            if datetime.now() - ctx.timestamp < timedelta(hours=24)
        ]
        
        return {
            'total_errors': len(self.error_history),
            'recent_errors_24h': len(recent_errors),
            'error_types': error_types,
            'severity_distribution': severity_counts,
            'circuit_breakers': {
                key: breaker['state'] 
                for key, breaker in self.circuit_breakers.items()
            }
        }
    
    def clear_error_history(self, older_than_hours: int = 24):
        """清理错误历史记录"""
        cutoff_time = datetime.now() - timedelta(hours=older_than_hours)
        self.error_history = [
            ctx for ctx in self.error_history
            if ctx.timestamp > cutoff_time
        ]
        self.logger.info(f"清理了{older_than_hours}小时前的错误记录")


# 全局错误处理器实例
error_handler = ErrorHandler()


def handle_errors(component: str = None, operation: str = None, 
                 context_data: Dict[str, Any] = None):
    """错误处理装饰器"""
    def decorator(func):
        if asyncio.iscoroutinefunction(func):
            async def async_wrapper(*args, **kwargs):
                try:
                    return await func(*args, **kwargs)
                except Exception as e:
                    comp = component or func.__module__
                    op = operation or func.__name__
                    return await error_handler.handle_error(e, comp, op, context_data)
            return async_wrapper
        else:
            def sync_wrapper(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    comp = component or func.__module__
                    op = operation or func.__name__
                    # 对于同步函数，创建异步任务处理错误
                    loop = asyncio.get_event_loop()
                    return loop.run_until_complete(
                        error_handler.handle_error(e, comp, op, context_data)
                    )
            return sync_wrapper
    return decorator